package com.framework.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.framework.core.common.bo.DictModel;
import com.framework.core.common.constant.CacheConstants;
import com.framework.core.common.enums.StatusEnum;
import com.framework.core.exception.CustomException;
import com.framework.system.entity.SysDict;
import com.framework.system.entity.SysDictItem;
import com.framework.system.entity.dto.SysDictAddDTO;
import com.framework.system.entity.dto.SysDictEditDTO;
import com.framework.system.entity.dto.SysDictQueryDTO;
import com.framework.system.entity.vo.SysDictListVO;
import com.framework.system.entity.vo.SysDictVO;
import com.framework.system.mapper.SysDictItemMapper;
import com.framework.system.mapper.SysDictMapper;
import com.framework.system.service.ISysDictService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典表 服务实现类
 * </p>
 *
 * @author Kevin
 * @since 2021-06-10
 */
@Service
@AllArgsConstructor
@Slf4j
public class SysDictServiceImpl implements ISysDictService {

    private SysDictMapper sysDictMapper;

    private SysDictItemMapper sysDictItemMapper;

    @Override
    public Page<SysDictListVO> selectPage(Page reqPage, SysDictQueryDTO req) {
        LambdaQueryWrapper<SysDict> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getDictCode()), SysDict::getDictCode, req.getDictCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getDictName()), SysDict::getDictName, req.getDictName());
        queryWrapper.orderByDesc(SysDict::getCreateTime);
        Page<SysDict> page = sysDictMapper.selectPage(reqPage, queryWrapper);
        Page<SysDictListVO> voPage = BeanUtil.copyProperties(page, Page.class);
        voPage.setRecords(BeanUtil.copyToList(page.getRecords(), SysDictListVO.class));
        return voPage;
    }

    @Override
    public List<SysDictListVO> selectList(SysDictQueryDTO req) {
        LambdaQueryWrapper<SysDict> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getDictCode()), SysDict::getDictCode, req.getDictCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getDictName()), SysDict::getDictName, req.getDictName());
        queryWrapper.orderByDesc(SysDict::getCreateTime);
        List<SysDict> list = sysDictMapper.selectList(queryWrapper);
        return BeanUtil.copyToList(list, SysDictListVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysDictAddDTO req) {
        if (!this.checkUniquedictName(req.getDictName(), null)) {
            throw new CustomException("字典名称已存在");
        }
        if (!this.checkUniqueDictCode(req.getDictCode(), null)) {
            throw new CustomException("字典编码已存在");
        }
        SysDict entity = BeanUtil.copyProperties(req, SysDict.class);
        sysDictMapper.insert(entity);
    }

    @CacheEvict(value = CacheConstants.CACHE_PREFIX_SYS_DICT, key = "#req.dictCode")
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysDictEditDTO req) {
        if (!this.checkUniquedictName(req.getDictName(), req.getId())) {
            throw new CustomException("字典名称已存在");
        }
        if (!this.checkUniqueDictCode(req.getDictCode(), req.getId())) {
            throw new CustomException("字典编码已存在");
        }
        SysDict entity = BeanUtil.copyProperties(req, SysDict.class);
        sysDictMapper.updateById(entity);
    }

    @CacheEvict(value = CacheConstants.CACHE_PREFIX_SYS_DICT, allEntries = true)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        idList.forEach(item -> {
            sysDictItemMapper.delete(Wrappers.lambdaQuery(SysDictItem.class).eq(SysDictItem::getDictId, item));
        });
        idList.forEach(item -> {
            sysDictMapper.deleteById(item);
        });
    }

    @Override
    public SysDictVO view(String id) {
        SysDict entity = sysDictMapper.selectById(id);
        return BeanUtil.copyProperties(entity, SysDictVO.class);
    }

    @Cacheable(value = CacheConstants.CACHE_PREFIX_SYS_DICT, key = "#dictCode", sync = true)
    @Override
    public List<DictModel> listDictModel(String dictCode) {
        SysDict sysDict = sysDictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, dictCode).eq(SysDict::getStatus, StatusEnum.YES.getCode()));
        if (Objects.isNull(sysDict)) {
            return new ArrayList();
        }
        List<SysDictItem> sysDictItemList = sysDictItemMapper.selectList(Wrappers.lambdaQuery(SysDictItem.class)
                .eq(SysDictItem::getDictId, sysDict.getId())
                .eq(SysDictItem::getStatus, StatusEnum.YES.getCode())
                .orderByAsc(SysDictItem::getSort));
        List<DictModel> dictModelList = sysDictItemList.stream().map(item -> {
            DictModel dictModel = new DictModel();
            dictModel.setLabel(item.getDictItemName());
            dictModel.setValue(item.getDictItemCode());
            return dictModel;
        }).collect(Collectors.toList());
        return dictModelList;
    }

    @CacheEvict(value = CacheConstants.CACHE_PREFIX_SYS_DICT, allEntries = true)
    @Override
    public void clearAllCache() {
        log.info("清除数据字典缓存");
    }

    private Boolean checkUniquedictName(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysDict entity = sysDictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictName, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniqueDictCode(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysDict entity = sysDictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

}
